package com.estock.platform.task.support;

import java.text.ParseException;

import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;

import com.estock.common.model.task.Task;
import com.estock.common.model.task.TaskRun;
import com.estock.common.model.task.enums.TaskFrequency;

/**
 * @author richard
 *
 */
public class TaskExecutor {
	
	private static final String TRIGGER_PREFIX_NAME = "taskTrigger";
	
	private static Scheduler scheduler; 

	public static void execute(Task task) throws SchedulerException {
		try {
			Class<?> clazz = Class.forName(task.getTaskInstance());
			Job job = (Job) clazz.newInstance();
			scheduleJob(task, job);
		} catch (Exception e) {
			throw new RuntimeException(
					"Wrong task name for initializing task class");
		}
	}

	private static void scheduleJob(Task task, Job job) {
		if (task.getId() == null) {
			throw new RuntimeException("You must persist task before execute it!");
		}
		try {
			Trigger trigger = TriggerFactory.getTrigger(task);
			
			if (trigger instanceof SimpleTrigger) {
				SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
				simpleTrigger.setStartTime(task.getNextSDateTime());
				if (task.getFrequency() == TaskFrequency.ONCE.getFrequency()) {
					simpleTrigger.setRepeatCount(0);
					simpleTrigger.setRepeatInterval(1000 * 5);
				} else {
					simpleTrigger.setRepeatInterval(task.getRepeatedInternal());
				}
			}
			
			if (trigger instanceof CronTrigger) {
				CronTrigger cronTrigger = (CronTrigger) trigger;
				cronTrigger.setCronExpression(task.getCronExpression());
			}
			
			if (scheduler == null) {
				scheduler = StdSchedulerFactory.getDefaultScheduler();
			}
			if (scheduler.getTrigger(trigger.getName(), Scheduler.DEFAULT_GROUP) == null) {
				JobDetail jobDetail=new JobDetail(task.getName(), Scheduler.DEFAULT_GROUP, job.getClass());
				JobDataMap dataMap = new JobDataMap();
				dataMap.put("taskrun", new TaskRun(task.getId()));
				jobDetail.setJobDataMap(dataMap);
				scheduler.scheduleJob(jobDetail, trigger);
			} else {
				trigger.setJobName(task.getName());
				scheduler.rescheduleJob(trigger.getName(), Scheduler.DEFAULT_GROUP, trigger);
			}
			
			scheduler.start();
			
		} catch (SchedulerException e) {
			e.printStackTrace();
		} catch (ParseException e) {
			e.printStackTrace();
		} 
	}
	
	
	static class TriggerFactory {
		static Trigger getTrigger(Task task) throws SchedulerException {
			if (task.isCustomFrequency()) {
				return new CronTrigger(generateTriggerName(task), Scheduler.DEFAULT_GROUP);
			}
			return new SimpleTrigger(generateTriggerName(task), Scheduler.DEFAULT_GROUP); 
		}
	}
	
	static String generateTriggerName(Task task) throws SchedulerException {
		return TRIGGER_PREFIX_NAME + task.getId();
	}

}
